package com.ccb.sc.common.modules.shopkeeper.service;

import cn.hutool.core.lang.UUID;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.google.common.collect.Lists;
//psl import com.ccb.sc.common.bind.exception.BizException;
import com.ccb.sc.common.bind.page.PageParams;
import com.ccb.sc.common.bind.page.PageVo;
import com.ccb.sc.common.code.BizCodeFace;
import com.ccb.sc.common.code.ErrorCode;
import com.ccb.sc.common.modules.common.service.IRedisService;
import com.ccb.sc.common.modules.member.enums.MemberStatus;
import com.ccb.sc.common.modules.shopkeeper.convert.ShopkeeperWithdrawConvert;
import com.ccb.sc.common.modules.shopkeeper.entity.Shopkeeper;
import com.ccb.sc.common.modules.shopkeeper.entity.ShopkeeperAuth;
import com.ccb.sc.common.modules.shopkeeper.entity.ShopkeeperWithdraw;
import com.ccb.sc.common.modules.shopkeeper.enums.ApplyStatus;
import com.ccb.sc.common.modules.shopkeeper.enums.ShopkeeperPointsLogType;
import com.ccb.sc.common.modules.shopkeeper.enums.WithdrawStatus;
import com.ccb.sc.common.modules.shopkeeper.enums.WithdrawType;
import com.ccb.sc.common.modules.shopkeeper.mapper.ShopkeeperWithdrawMapper;
import com.ccb.sc.common.modules.shopkeeper.vo.ShopkeeperWithdrawListVo;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.Assert;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;

import java.math.BigDecimal;
import java.util.List;
import java.util.Objects;

/**
 * <p>
 * 店主提现记录 服务实现类
 * </p>
 *
 * @author ken
 * @since 2023-02-12
 */
@Service
public class ShopkeeperWithdrawService extends ServiceImpl<ShopkeeperWithdrawMapper, ShopkeeperWithdraw> {

    private ShopkeeperService shopkeeperService;

    private ShopkeeperAuthService shopkeeperAuthService;

    private ShopkeeperPointsLogService shopkeeperPointsLogService;

    private IRedisService redisService;

    private static final BigDecimal AUTO_PAYMENT_THRESHOLD = new BigDecimal("1000");

    public PageVo<ShopkeeperWithdrawListVo> searchByQueryParam(Long shopkeeperId, PageParams queryParam) {
        Page<ShopkeeperWithdraw> page = new Page<ShopkeeperWithdraw>(queryParam.getCurrent(), queryParam.getPageSize());
        Page<ShopkeeperWithdraw> pointsLogPage = this.page(page, Wrappers.<ShopkeeperWithdraw>lambdaQuery()
                .eq(ShopkeeperWithdraw::getShopkeeperId, shopkeeperId)
                .orderByDesc(ShopkeeperWithdraw::getId));
        List<ShopkeeperWithdraw> records = pointsLogPage.getRecords();
        if (CollectionUtils.isEmpty(records)) {
            return PageVo.create(queryParam.getCurrent(), queryParam.getPageSize(), 0, Lists.newArrayList());
        }
        List<ShopkeeperWithdrawListVo> list = ShopkeeperWithdrawConvert.INSTANCE.entity2ListVo(records);
        return PageVo.create(queryParam.getCurrent(), queryParam.getPageSize(), page.getTotal(), list);
    }

    @Transactional(rollbackFor = Exception.class)
    public void withdraw(Long shopkeeperId, BigDecimal amount) {
        Assert.isTrue(amount.compareTo(BigDecimal.ZERO) > 0, "提现金额需大于0");
        // 校验阳光值，目前1阳光值=1元
        Shopkeeper shopkeeper = this.shopkeeperService.getById(shopkeeperId);
        Assert.isTrue(!MemberStatus.DISABLED.equals(shopkeeper.getStatus()), "账号异常，请联系客服！");
        ShopkeeperAuth shopkeeperAuth = this.shopkeeperAuthService.findByShopkeeperId(shopkeeperId);
        Assert.isTrue(shopkeeperAuth != null && Objects.equals(ApplyStatus.SUCCESS, shopkeeperAuth.getStatus()), "请先实名认证！");
        Assert.isTrue(StringUtils.hasText(shopkeeperAuth.getAlipayAccount()), "请先修改支付宝账号");
        String redisKey = String.format("lock:award:%s:%s", ShopkeeperPointsLogType.WITHDRAW.getValue(), shopkeeperId);
        String randomStr = UUID.randomUUID().toString();
        try {
            boolean lock = this.redisService.lock(redisKey, randomStr, 10);
            if (!lock) {
                //psl throw new BizException(BizCodeFace.createBizCode(ErrorCode.FAST_FREQUENCY));
            }
            Assert.isTrue(shopkeeper.getPoints().compareTo(BigDecimal.ZERO) > 0 && shopkeeper.getPoints().compareTo(amount) >= 0, "账户余额不足！");

            ShopkeeperWithdraw withdraw = new ShopkeeperWithdraw();
            withdraw.setShopkeeperId(shopkeeperId);
            withdraw.setAmount(amount);
            withdraw.setPoints(amount);
            withdraw.setWithdrawType(WithdrawType.ALIPAY);
            withdraw.setAccount(shopkeeperAuth.getAlipayAccount());
            withdraw.setStatus(WithdrawStatus.WAIT);
            Assert.isTrue(this.save(withdraw), "提现申请失败，请稍后重试！");

            // 扣除阳光值
            this.shopkeeperPointsLogService.award(shopkeeperId, BigDecimal.ZERO.subtract(amount),
                    ShopkeeperPointsLogType.WITHDRAW, String.valueOf(withdraw.getId()), shopkeeper.getMemberId());

            /*if (amount.compareTo(AUTO_PAYMENT_THRESHOLD) <= 0) {
                // todo 小于1000走支付宝自动打款 并记录转账流水
                withdraw.setStatus(WithdrawStatus.AUTO_PAYMENT);
                withdraw.setAuditTime(LocalDateTime.now());
                this.updateById(withdraw);
            }*/
        }finally {
            boolean unLock = this.redisService.unLock(redisKey, randomStr);
            if (!unLock) {
                this.redisService.unLock(redisKey, randomStr);
            }
        }
    }

    @Autowired
    public void setShopkeeperService(ShopkeeperService shopkeeperService) {
        this.shopkeeperService = shopkeeperService;
    }

    @Autowired
    public void setShopkeeperAuthService(ShopkeeperAuthService shopkeeperAuthService) {
        this.shopkeeperAuthService = shopkeeperAuthService;
    }

    @Autowired
    public void setShopkeeperPointsLogService(ShopkeeperPointsLogService shopkeeperPointsLogService) {
        this.shopkeeperPointsLogService = shopkeeperPointsLogService;
    }

    @Autowired
    public void setRedisService(IRedisService redisService) {
        this.redisService = redisService;
    }
}
